﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Web;

using umbraco;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.packager.standardPackageActions;
using umbraco.interfaces;

namespace CreativeMinds.Umbraco.Installation.PackageActions {

	/// <summary>
	/// The package action will add a piece of xml (given as part of the action xml) to the ui.xml file that stores
	/// information for the different node types in the Umbraco UI trees. The information dictates which usercontrol
	/// to use for creating new nodes and which Task methods to use when creating or deleting nodes.
	/// 
	/// Example xml can be found in the resource files
	/// </summary>
	public class AddTreeNodeType : PackageAction, IPackageAction {
		private const string uiFilePath = "/umbraco/config/create/ui.xml";

		/// <summary>
		/// The alias of the package. This alias must be unique and is use to identify the package action to use.
		/// </summary>
		/// <returns>The alias of the package</returns>
		public override string Alias() {
			return "AddTreeNodeType";
		}

		/// <summary>
		/// Install method for the package.
		/// </summary>
		/// <param name="packageName">Name of the package to be installed.</param>
		/// <param name="xmlData">The node for the package from the actions xml.</param>
		/// <returns>True if the installation succeeded</returns>
		protected override bool Install(string packageName, XmlNode xmlData) {
			// Get the UI xml file.
			XmlDocument ui = GetUIData();

			XmlNode root = ui.SelectSingleNode("createUI");
			// Get all node types from the action xml.
			XmlNodeList nodeTypes = xmlData.SelectNodes("nodeType");

			foreach (XmlNode nodeType in nodeTypes) {
				try {
					// Alias of the nodeType we're looking for.
					string alias = nodeType.Attributes.GetNamedItem("alias").Value;

					// Check to see if that node type already existing in the UI xml.
					XmlNode existing = ui.SelectSingleNode(String.Format("createUI/nodeType[@alias='{0}']", alias));
					if (existing != null) {
						// The node type already exists, let's change the content (header, usercontrol, tasks nodes etc.)
						existing.InnerXml = nodeType.InnerXml;
					}
					else {
						// Node type unknown, let's create a new xml node for it!
						XmlNode newNode = ui.CreateElement("nodeType");
						root.AppendChild(newNode);
						newNode.InnerXml = nodeType.InnerXml;

						// Set the alias on the new xml node.
						XmlAttribute aliasAttr = ui.CreateAttribute("alias");
						newNode.Attributes.Append(aliasAttr);
						aliasAttr.Value = alias;
					}
				}
				catch (Exception ex) {
					// An error occured, let's bail out without saving any changes!
					Log.Add(LogTypes.Error, -1, String.Format("{1}{0}{2}{0}{3}", Environment.NewLine, ex.TargetSite, ex.Message, ex.StackTrace));
					return false;
				}
			}

			// Save the changes!
			SaveUIData(ui);
			return true;
		}

		private void SaveUIData(XmlDocument xml) {
			// Save the xml back to the ui.xml file!
			xml.Save(HttpContext.Current.Server.MapPath(uiFilePath));
		}

		private XmlDocument GetUIData() {
			// Read the ui.xml file
			return xmlHelper.OpenAsXmlDocument(uiFilePath);
		}

		/// <summary>
		/// Uninstall method for the package.
		/// </summary>
		/// <param name="packageName">Name of the package to be uninstalled.</param>
		/// <param name="xmlData">The node for the package from the actions xml.</param>
		/// <returns>True if the uninstallation succeeded</returns>
		protected override bool Uninstall(string packageName, XmlNode xmlData) {
			// Get the UI xml file.
			XmlDocument ui = GetUIData();

			XmlNode root = ui.SelectSingleNode("createUI");
			// Get all node types from the action xml.
			XmlNodeList nodeTypes = xmlData.SelectNodes("nodeType");

			foreach (XmlNode nodeType in nodeTypes) {
				try {
					// Alias of the nodeType we're looking for.
					string alias = nodeType.Attributes.GetNamedItem("alias").Value;

					// Check to see if that node type already existing in the UI xml.
					XmlNode existing = ui.SelectSingleNode(String.Format("createUI/nodeType[@alias='{0}']", alias));
					if (existing != null) {
						// Node exists, let's remove the node (and all children).
						root.RemoveChild(existing);
					}
				}
				catch (Exception ex) {
					// An error occured, let's bail out without saving any changes!
					Log.Add(LogTypes.Error, -1, String.Format("{1}{0}{2}{0}{3}", Environment.NewLine, ex.TargetSite, ex.Message, ex.StackTrace));
					return false;
				}
			}

			// Save the changes!
			SaveUIData(ui);
			return true;
		}

		/// <summary>
		/// Returns a sample xml node, in this case the node data for the Documents tree.
		/// </summary>
		/// <returns>A xml node containing an example of the required data for this package</returns>
		public override XmlNode SampleXml() {
			return helper.parseStringToXmlNode(String.Format(Resource1.AddTreeNodeType, this.Alias()));
		}
	}
}